#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include "array.h"
#include "string.h"
#include "xmalloc.h"

string_t *
create_empty_string(void)
{
  return (create_nstring("", 0));
}

string_t *
create_string(const char *s)
{
  return (create_nstring(s, strlen(s)));
}

string_t *
create_nstring(const char *s, size_t len)
{
  string_t *str = (string_t *) array_create(sizeof(char), STR_INITSIZ);
  set_nstring(str, s, len);
  return (str);
}

string_t *
create_fstring(const char *fmt, ...)
{
  va_list ap;
  string_t *res = NULL;
  char *s = NULL;

  va_start(ap, fmt);
  vasprintf(&s, fmt, ap);
  va_end(ap);
  res = create_string(s);
  free(s);
  return (res);
}

string_t *
create_dupstring(string_t *src)
{
  return ( create_string(get_string(src)) );
}

void
free_string(string_t *str)
{
  array_free((string_t *)str);
  str = NULL;
}

__inline__ void
set_string(string_t *dst, const char *s)
{
  set_nstring(dst, s, strlen(s));
}

__inline__ void
set_nstring(string_t *dst, const char *s, size_t len)
{
  if (!dst || !dst->data || !s) return;
  array_set_data(dst, (void *)s, len + 1);
  *((char *)array_last(dst) - 1) = '\0';
}

void
set_fstring(string_t *dst, const char *fmt, ...)
{
  va_list ap;
  char *s = NULL;

  va_start(ap, fmt);
  vasprintf(&s, fmt, ap);
  va_end(ap);
  set_string(dst, s);
  free(s);
}

__inline__ const char *
get_string(string_t *dst)
{
  if (!dst || !dst->data) return ("");
  const char *s = (const char *)dst->data;
  return ( (s ? s : "") );
}

__inline__ size_t
get_strlen(string_t *dst)
{
  if (!dst) return (0);
  return ( array_used_abs(dst) - 1 );
}

__inline__ const char *
get_string_off(string_t *dst, size_t idx)
{
  return ( (const char *)array_get_offset(dst, idx) );
}

int
string_cmp(string_t *haystack, const char *needle, int start_idx)
{
  const char *str = get_string(haystack), *tmp;
  size_t len = get_strlen(haystack);

  if (len < (size_t)start_idx || start_idx < 0) return (-1);
  tmp = strstr((char *)(str + start_idx), needle);
  if (tmp) {
    return (tmp - str);
  } else {
    return (-1);
  }
}

__inline__ void
add_string(string_t *dst, const char *s)
{
  add_nstring(dst, s, strlen(s));
}

__inline__ void
add_sstring(string_t *dst, string_t *src)
{
  add_nstring(dst, get_string(src), get_strlen(src));
}

__inline__ void
add_nstring(string_t *dst, const char *s, size_t len)
{
  if (!dst || !dst->data || !s) return;
  array_delete_data(dst, get_strlen(dst), 1);
  array_add_data(dst, (void *)s, len + 1);
  *((char *)(array_last(dst)) - 1) = '\0';
}

void
add_fstring(string_t *dst, const char *fmt, ...)
{
  va_list ap;
  char *s = NULL;

  va_start(ap, fmt);
  vasprintf(&s, fmt, ap);
  va_end(ap);
  add_string(dst, s);
  free(s);
}

void
del_string(string_t *dst, size_t index, size_t len)
{
  size_t slen;

  if (!dst) return;
  slen = get_strlen(dst);
  if ( (index) >= slen ) return;
  if ( (index+len) > slen ) return;
  array_delete_data(dst, index, len);
  *((char *)array_last(dst) - 1) = '\0';
}

__inline__ void
insert_string(string_t *dst, size_t index, const char *data, size_t data_len)
{
  if (!dst || !data) return;
  array_insert_data(dst, index, (void *)data, data_len);
  *((char *)array_last(dst) - 1) = '\0';
}

int
replace_string(string_t *dst, const char *needle, const char *replacer, size_t replen)
{
  char *str = NULL, *start = NULL, *found = NULL;
  size_t len, pos = 0;
  int count = 0;

  if (dst && needle && replacer)
  {
    str = (char *)get_string(dst);
    start = str;
    len = strlen(needle);

    while ( (found = strstr(start, needle)) != NULL )
    {
      pos = (found - str);
      del_string(dst, pos, len);
      insert_string(dst, pos, (void *)replacer, replen);

      str = (char *)get_string(dst);
      start = (char *)(str + pos + replen);
      count++;
    }
  }
  return (count);
}


#ifdef ENABLE_DEBUG
void
print_string_debug(string_t *dst)
{
  array_print_debug(dst);
  fprintf(stderr, "  content: %s\n", get_string(dst));
}
#endif

